package com.insight.modules.system.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.insight.common.api.vo.Result;
import com.insight.common.util.*;
import com.insight.modules.umpPwdManage.entity.UmpPwdManage;
import com.insight.modules.umpPwdManage.service.IUmpPwdManageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("/sys/common")
public class CommonController {

    // 读取配置文件中上传路径属性（如：D:/upload/）
    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;

    // 注入UMP密码管理服务，用于操作密码相关数据
    @Autowired
    private IUmpPwdManageService iUmpPwdManageService;


    /**
     * 无权限访问接口
     *
     * 当用户请求未授权资源时，返回无权限提示信息
     *
     * @return 统一封装的错误提示结果
     */
    @GetMapping("/403")
    public Result<?> noauth() {
        return Result.error("没有权限，请联系管理员授权");
    }


    /**
     * 文件上传统一处理方法
     *
     * 支持通过请求参数"biz"自定义上传子目录，
     * 支持参数"isRequireMd5"控制是否返回上传文件的MD5值。
     *
     * @param request  HttpServletRequest请求对象，获取文件和参数
     * @param response HttpServletResponse响应对象
     * @return 统一封装的上传结果，成功返回文件路径或MD5，失败返回错误信息
     */
    @PostMapping(value = "/upload")
    public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
        Result<?> result = new Result<>();
        String savePath = "";
        // 获取业务路径biz参数，支持自定义上传目录
        String bizPath = request.getParameter("biz");
        // 是否需要返回文件的md5值，"true"表示需要
        String isRequireMd5 = request.getParameter("isRequireMd5");
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 获取上传文件对象
        MultipartFile file = multipartRequest.getFile("file");
        // 原始文件名
        String fileOriginalName = file.getOriginalFilename();

        // 如果bizPath为空或者值为"temp"，置空bizPath（即默认上传根目录）
        if (oConvertUtils.isEmpty(bizPath) || "temp".equals(bizPath)) {
            bizPath = "";
        }
        // 调用工具类上传文件，返回存储路径
        savePath = CommonUtils.upload(file, bizPath, null);

        if (oConvertUtils.isNotEmpty(savePath)) {
            // 上传成功
            JSONObject json = new JSONObject();
            // 判断是否需要返回md5值
            if (StringUtils.isNotBlank(isRequireMd5) && Boolean.parseBoolean(isRequireMd5)){
                try {
                    // 计算文件MD5值
                    String md5 = MD5Util.fileToMD5(file.getInputStream());
                    json.put("md5", md5);
                    json.put("fileOriginalName", fileOriginalName);
                } catch (IOException e) {
                    throw new IllegalArgumentException("文件读取失败，请检查文件是否已损坏或权限异常", e);
                } catch (NoSuchAlgorithmException e) {
                    throw new IllegalStateException("加密算法初始化失败：系统环境异常", e);
                }
                json.put("savePath", savePath);
                // 将json字符串设置到返回消息
                result.setMessage(json.toJSONString());
            } else {
                // 不返回MD5，直接返回路径
                result.setMessage(savePath);
                result.setSuccess(true);
            }
        } else {
            // 上传失败
            result.setMessage("上传失败！");
            result.setSuccess(false);
        }
        return result;
    }


    /**
     * 预览图片或者下载文件
     * 访问路径示例：http://localhost:8080/common/static/{路径及文件名}
     * 该接口根据文件名从服务器读取文件并写出响应，实现预览或下载
     *
     * @param filename 文件名（可选，部分前端可能传）
     * @param request  HttpServletRequest请求对象
     * @param response HttpServletResponse响应对象
     */
    @GetMapping(value = "/static/**")
    public void view(@RequestParam(value = "filename", required = false) String filename, HttpServletRequest request, HttpServletResponse response) {
        try {
            if (request == null || response == null || filename == null) {
                if (response != null) {
                    response.setStatus(404);
                }
                return;
            }
            CommonUtils.download(filename, request, response);
        } catch (Exception e) {
            log.error("获取文件失败" + e.getMessage());
            if (response != null) {
                response.setStatus(404);
            }
            e.printStackTrace();
        }
    }

    /**
     * 下载文件接口
     * 请求路径示例：http://localhost:8080/common/download/{路径及文件名}
     *
     * @param request  请求对象
     * @param response 响应对象
     * @throws Exception 处理文件读取异常
     */
    @GetMapping(value = "/download/**")
    public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
        CommonUtils.download(request, response);
    }

    /**
     * 下载文件接口（功能与上面download相同，建议确认前端调用频率，考虑合并）
     *
     * @param request  请求对象
     * @param response 响应对象
     * @throws Exception 异常抛出
     */
    @GetMapping(value = "/downloadFile/**")
    public void downloadFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
        CommonUtils.download(request, response);
    }


    /**
     * PDF文件预览IFrame页面跳转
     * 返回名为"pdfPreviewIframe"的视图页面，通常用于前端嵌入PDF预览
     *
     * @param modelAndView ModelAndView视图封装对象
     * @return 视图页面信息
     */
    @RequestMapping("/pdf/pdfPreviewIframe")
    public ModelAndView pdfPreviewIframe(ModelAndView modelAndView) {
        modelAndView.setViewName("pdfPreviewIframe");
        return modelAndView;
    }


    /**
     * HTTP请求中转，解决跨域问题
     *
     * 根据传入的url参数，将请求转发到目标地址，
     * 并将响应结果返回给调用方，实现前端跨域调用后台接口。
     *
     * @param url     必填，目标请求地址
     * @param request 当前HttpServletRequest请求对象
     * @return 统一封装的请求结果
     */
    @RequestMapping("/transitRESTful")
    public Result transitRESTful(@RequestParam("url") String url, HttpServletRequest request) {
        try {
            if (request == null || url == null) {
                return Result.error("请求参数无效");
            }
            ServletServerHttpRequest httpRequest = new ServletServerHttpRequest(request);
            HttpMethod method = httpRequest.getMethod();
            if (method == null) {
                return Result.error("HTTP方法不能为空");
            }
            JSONObject params;
            try {
                InputStream body = httpRequest.getBody();
                params = JSON.parseObject(JSON.toJSONString(body));
            } catch (Exception e) {
                params = new JSONObject();
            }
            JSONObject variables = JSON.parseObject(JSON.toJSONString(request.getParameterMap()));
            if (variables != null) {
                variables.remove("url");
            } else {
                variables = new JSONObject();
            }
            String token = TokenUtils.getTokenByRequest(request);
            HttpHeaders headers = new HttpHeaders();
            headers.set("X-Access-Token", token);
            String httpURL = URLDecoder.decode(url, "UTF-8");
            ResponseEntity<String> response = RestUtil.request(httpURL, method, headers, variables, params, String.class);
            Result<Object> result = new Result<>();
            int statusCode = response.getStatusCodeValue();
            result.setCode(statusCode);
            result.setSuccess(statusCode == 200);
            String responseBody = response.getBody();
            try {
                if (responseBody == null){
                    result.setMessage("请求失败");
                }
                Object json = JSON.parse(responseBody);
                result.setResult(json);
            } catch (Exception e) {
                result.setResult(responseBody);
            }
            return result;
        } catch (Exception e) {
            log.debug("中转HTTP请求失败", e);
            return Result.error(e.getMessage());
        }
    }


    /**
     * 音频文件上传接口
     *
     * 根据参数type决定上传路径及更新数据库中对应字段。
     *
     * @param request  请求对象，包含文件
     * @param response 响应对象
     * @param type     类型，"10"表示常规，其他为严重
     * @return 上传结果封装，成功包含路径，失败提示上传失败
     */
    @PostMapping(value = "/upload1")
    public Result<?> upload1(HttpServletRequest request, HttpServletResponse response, String type) {
        System.out.println(type);
        Result<?> result = new Result<>();
        String savePath = "";
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
        savePath = this.uploadLocal1(file, type);
        if (oConvertUtils.isNotEmpty(savePath)) {
            result.setMessage(savePath);
            result.setSuccess(true);
        } else {
            result.setMessage("上传失败！");
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * 私有辅助方法：本地上传音频文件，更新数据库路径
     *
     * 根据type字段将文件分别保存为"commonly"或"serious"命名，并更新所有UmpPwdManage记录对应字段。
     *
     * @param file 文件对象
     * @param type 类型编码
     * @return 上传后数据库存储路径，失败返回空字符串
     */
    private String uploadLocal1(MultipartFile file, String type) {
        try {
            String ctxPath = uploadpath;  // 基础上传目录
            File file1 = new File(ctxPath + File.separator + File.separator);
            if (!file1.exists()) {
                file1.mkdirs();// 创建目录
            }
            // 获取上传文件名，剥离路径，仅保留文件名
            String orgName = file.getOriginalFilename();
            orgName = CommonUtils.getFileName(orgName);
            // 文件后缀名，如.mp3
            String substring = orgName.substring(orgName.lastIndexOf('.'));
            // 查询所有密码管理数据
            List<UmpPwdManage> list = iUmpPwdManageService.list();
            String fileName;
            if ("10".equals(type)) {
                // 常规类型命名
                fileName = uploadpath + "/commonly" + substring;
                for (UmpPwdManage umpPwdManage : list) {
                    umpPwdManage.setCommonly(fileName);
                    iUmpPwdManageService.updateById(umpPwdManage);
                }
            } else {
                // 严重类型命名
                fileName = uploadpath + "/serious" + substring;
                for (UmpPwdManage umpPwdManage : list) {
                    umpPwdManage.setSerious(fileName);
                    iUmpPwdManageService.updateById(umpPwdManage);
                }
            }
            // 文件保存绝对路径
            String savePath = file1.getPath() + File.separator + fileName;
            File savefile = new File(savePath);
            // 将文件写入磁盘
            FileCopyUtils.copy(file.getBytes(), savefile);
            // 返回数据库存储路径，替换Windows路径分隔符为Unix格式
            String dbpath = fileName;
            if (dbpath.contains("\\")) {
                dbpath = dbpath.replace("\\", "/");
            }
            return dbpath;
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return "";
    }

    /**
     * 删除文件接口
     *
     * 支持一次删除多个文件，文件路径用逗号分割
     *
     * @param files 多个文件路径字符串，逗号分隔
     * @return 删除成功返回true，否则false
     */
    @DeleteMapping(value = "/delete")
    public boolean deleteFile(@RequestParam String files) {
        return CommonUtils.deleteFile(Arrays.asList(files.split(",")));
    }

}

